#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdarg.h"
#include "parser.tab.h"
#include <math.h>
#include <ctype.h>

#define MAXLENGTH   200
#define DX 3*sizeof(int)          /*活动记录控制信息需要的单元数，这个根据实际系统调整*/
#define INTEGER_MINVALUE -2147483648
#define BLOCK -2147483647
#define ARRAY_LEN 10
#define boolean -17
//以下语法树结点类型、三地址结点类型等定义仅供参考，实验时一定要根据自己的理解来定义
//int LEV;      //层号

enum node_kind{
	EXT_DEF_LIST,
	EXT_VAR_DEF,
	FUNC_DEF,
	FUNC_DEC,
	EXT_DEC_LIST,
	PARAM_LIST,
	PARAM_DEC,
	VAR_DEF,
	DEC_LIST,
	DEF_LIST,
	COMP_STM,
	STM_LIST,
	EXP_STMT,
	IF_THEN,
	IF_THEN_ELSE,
	FUNC_CALL,
	ARGS,
	FUNCTION,
	PARAM,
	ARG,
	CALL,
	LABEL,
	GOTO,
	JLT,
	JLE,
	JGT,
	JGE,
	EQ,
	NEQ,
	ARRAY_DEC,
	FOR_DEC,
	CONTINUE_NODE,
	BREAK_NODE,
	BLANK,
	ARRAY_DF,
	/*FOR_EXP1,
	FOR_EXP2,
	FOR_EXP3,*/
	FOR_NODE,
	ARRAY_CALL
};

struct opn {
	int kind;    //标识联合成员的属性
	int type;    //标识操作数的数据类型
	union {
		int     const_int;      //整常数值，立即数
		float   const_float;    //浮点常数值，立即数
		char    const_char[3];     //字符常数值，立即数
		char    id[33];         //变量或临时变量的别名或标号字符串
	};
	int level;                  //变量的层号，0表示是全局变量，数据保存在静态数据区
	int offset;                 //偏移量，目标代码生成时用
};

typedef struct codenode {   //三地址TAC代码结点,采用单链表存放中间语言代码
	int  op;
	struct opn opn1, opn2, result;
	struct codenode* next, * prior;
} codenode;

struct ASTNode {
	//以下对结点属性定义没有考虑存储效率，只是简单地列出要用到的一些属性
	//int kind;
	enum node_kind kind;  //节点类型
	union {
		char type_id[33];             //由标识符生成的叶结点
		int type_int;                 //由整常数生成的叶结点
		float type_float;               //由浮点常数生成的叶结点
		char type_char[3];  //由字符类型生成的叶节点
	};
	struct ASTNode* ptr[4];         //由kind确定有多少棵子树
	int place;                     //存放（临时）变量在符号表的位置序号
	char Etrue[15], Efalse[15];       //对布尔表达式的翻译时，真假转移目标的标号
	char Snext[15];               //结点对应语句S执行后的下一条语句位置标号
	struct codenode* code;          //该结点中间代码链表头指针
	int type;                      //用以标识表达式结点的类型
	int pos;                       //语法单位所在位置行号
	int offset;                     //偏移量
	int width;                     //占数据字节数
	int num;                      //计数器，可以用来统计形参个数
};

struct symbol {       //这里只列出了一个符号表项的部分属性，没考虑属性间的互斥
	char name[33];   //变量或函数名
	int level;        //层号，外部变量名或函数名为0，形参为1，入栈即复合语句+1，出-1
	int type;         //变量类型或函数返回值类型
	int  paramnum;  //对函数适用，记录形式参数个数
	char alias[10];   //别名，为解决嵌套层次使用
	char flag;       //符号标记，函数：'F'  变量：'V'   参数：'P'  临时变量：'T'
	int offset;      //外部变量和局部变量在其静态数据区或活动记录中的偏移量，
	//或记录函数活动记录大小，目标代码生成时使用
		//函数入口等实验可能会用到的属性...
	int array[ARRAY_LEN];  //记录数组维度
};


//符号表，这里设置为顺序栈，index初值为0
struct symboltable {
	struct symbol symbols[MAXLENGTH];
	int index;
} symbolTable;

//使用顺序栈来管理continue和break
struct breaktable{
	struct codenode * breaks[MAXLENGTH];
	int index;
} breakTable;

struct continuetable{
	struct codenode * continues[MAXLENGTH];
	int index;
} continueTable;

struct symbol_scope_begin {
	//当前作用域的符号在符号表的起始位置序号,这是一个栈结构,当使用顺序表作为符号表时，进入、退出一个作用域时需要对其操作，以完成符号表的管理。对其它形式的符号表，不一定需要此数据结构
	int TX[30];
	int top;
} symbol_scope_TX;

struct dead
{
	char label[20]; //存储变量名
	int flag;
	int nlines;	 //记录出现次数
	int line[20]; //记录出现位置
} var[255];	 //变量结构

typedef struct hash{
	char label[20];  //变量名
	int val;  //值
	struct hash * next;
}hash;

struct ASTNode* mknode(int num, int kind, int pos, ...);

void semantic_Analysis0(struct ASTNode *T);
void semantic_Analysis(struct ASTNode *T);
void boolExp(struct ASTNode *T);
void Exp(struct ASTNode *T);
void callArray(struct ASTNode* T);
void objectCode(struct codenode *head);

int fillSymbolTable(char* name, char* alias, int level, int type, char flag, int offset);
void semantic_error(int line, char* msg1, char* msg2);
int searchSymbolTable(char* name);

char* strcat0(char* s1, char* s2);
char* newAlias();
char* newLabel();
char* newTemp();

void prn_symbol();
int fill_Temp(char* name, int level, int type, char flag, int offset);
void ext_var_list(struct ASTNode* T);
int  match_param(int i, struct ASTNode* T);

struct codenode* genIR(int op, struct opn opn1, struct opn opn2, struct opn result);
struct codenode* genLabel(char* label);
struct codenode* genGoto(char* label);
struct codenode* merge(int num, ...);
void prnIR(struct codenode* head);
int calArrayNums(struct ASTNode * T);
int fillArray(struct ASTNode * T, int * array, int index);
int calArrayWidth(struct ASTNode *T,int *array,int index);
int calArrayPerWidth(int *array,int index);

int find(char *s);
void getLiveCode(FILE *f, FILE *g);
int isBeginWith(const char *str1, char *str2);
int isSPStatement(char *str);
int containsLBRB(char * str);
void deadCode(int l);
void optimize(int l,hash * head,FILE * f);
int tokenize(char *str);
hash * insert(hash * head , char * key ,int val);
int getValue(hash * head,char * key);
int optimize_main();

codenode * splitBlock(codenode * head);
int * findAllGOTOLabel(codenode * head);
codenode *genBlock(char *label);
char *newBlock();

